package org.yoome.jtools.distributelock;

import org.yoome.jtools.utils.ApplicationContextUtil;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.util.StringUtils;

import java.util.Objects;
import java.util.UUID;

public class LockMethodInterceptor implements MethodInterceptor {

    private DistributedLock lock;

    public LockMethodInterceptor(DistributedLock lock) {
        this.lock = lock;
    }

    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        if (Objects.isNull(methodInvocation)
                || Objects.isNull(methodInvocation.getMethod())) {
            throw new Exception("找不到方法");
        }
        AutoDistributeLock distributedLock
                = methodInvocation.getMethod().getAnnotation(AutoDistributeLock.class);
        if (Objects.isNull(distributedLock)) {
            throw new Exception("找不到锁");
        }
        String key = distributedLock.key();
        Class keyGeneratorType = distributedLock.keyGenerator();
        long expireTime = distributedLock.expireTime();
        Object[] arguments = methodInvocation.getArguments();
        if (StringUtils.isEmpty(key)
                && DistributedKeyGenerator.class.isAssignableFrom(keyGeneratorType)) {
            DistributedKeyGenerator keyGenerator
                    = (DistributedKeyGenerator) ApplicationContextUtil.getBean(keyGeneratorType);
            if (Objects.isNull(keyGenerator)) {
                keyGenerator = (DistributedKeyGenerator)keyGeneratorType.newInstance();
            }
            key = keyGenerator.generateKey(arguments);
        }

        if (StringUtils.isEmpty(key)) {
            throw new Exception("key 不能为空");
        }

        String uid = UUID.randomUUID().toString();
        boolean acquire = this.lock.lock(key, uid);
        if (!acquire) {
            throw new Exception("获取分布式锁失败");
        }

        Object proceed = methodInvocation.proceed();
        boolean release = lock.unlock(key, uid);
        if (!release) {
            throw new Exception("释放锁失败");
        }

        return proceed;
    }
}
